use crate::models::news_search::*;
use axum::{extract::Query, Json};
use regex::Regex;
use std::fs;

#[derive(Clone)]
pub struct NewsSearchService {
    news_xml_path: String,
}

impl NewsSearchService {
    pub fn new(news_xml_path: String) -> Self {
        Self {
            news_xml_path
        }
    }

    pub async fn search_news_by_keywords(
        &self,
        Query(params): Query<SearchParams>,
    ) -> Json<Vec<NewsMeta>> {
        let mut results = Vec::new();
        let datas_path = &self.news_xml_path;
        let keyword = &params.keyword;

        for entry in fs::read_dir(datas_path).unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            if path.extension().map(|x| x == "xml").unwrap_or(false) {
                let xml_str = fs::read_to_string(&path).unwrap_or_default();
                let title = extract_tag(&xml_str, "title").unwrap_or_default();
                let all_keywords = extract_all_keywords(&xml_str);

                if title.contains(keyword) || all_keywords.iter().any(|k| k.contains(keyword)) {
                    if let Ok(meta) = extract_metadata(&xml_str) {
                        results.push(meta);
                    }
                }
            }
        }

        Json(results)
    }
}

fn extract_metadata(xml: &str) -> Result<NewsMeta, ()> {
    let title = extract_tag(xml, "title").unwrap_or_default();
    let url = extract_tag(xml, "url").unwrap_or_default();
    let publish_time = extract_tag(xml, "publish_time").unwrap_or_default();
    let source = extract_tag(xml, "source").unwrap_or_default();
    Ok(NewsMeta {
        title,
        url,
        publish_time,
        source,
    })
}

// 提取所有关键词（global和paragraphs）
fn extract_all_keywords(xml: &str) -> Vec<String> {
    let mut keywords = Vec::new();
    let re = Regex::new(r#"<keyword[^>]*>([^<]+)</keyword>"#).unwrap();
    for cap in re.captures_iter(xml) {
        if let Some(k) = cap.get(1) {
            keywords.push(k.as_str().to_string());
        }
    }
    keywords
}

fn extract_tag(xml: &str, tag: &str) -> Option<String> {
    let start = xml.find(&format!("<{}>", tag))? + tag.len() + 2;
    let end = xml[start..].find(&format!("</{}>", tag))? + start;
    Some(xml[start..end].to_string())
}
